package xinhao.lr.lr1;

import xinhao.Production;
import xinhao.Symbol;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author by xinhao  2021/8/24
 * LR(1) 文法的项目
 * [A→α·β, a]
 * 其中`A→αβ` 是一个产生式，`a` 是一个终结符,表示该项的展望符
 */
public class ProductionItem implements Comparable<ProductionItem> {
    public static final String ITEM_SYMBOL = "•";

    /** 项目对应的产生式 */
    private final Production production;

    /** 表示当前项目对应的位置，即圆点的位置。*/
    private final int pos;

    /** 表示当前pos位置对应的字符。 */
    private final Symbol posSymbol;

    /**
     * 当前项目的展望符
     */
    private final Symbol expectSymbol;

    /**
     * 这个产生式项目的标签
     * 也是这个产生式项目是否相等判断的依据
     */
    private final String label;

    private ProductionItem(Production production, int pos, Symbol posSymbol,
                          Symbol expectSymbol, String label) {
        this.production = production;
        this.pos = pos;
        this.posSymbol = posSymbol;
        this.expectSymbol = expectSymbol;
        this.label = label;
    }

    public static ProductionItem createByProduction(Production production, Symbol expectSymbol) {
        return create(production, expectSymbol, 0);
    }

    public static ProductionItem createNextByItem(ProductionItem item) {
        return create(item.production, item.expectSymbol, item.pos + 1);
    }

    private static ProductionItem create(Production production, Symbol expectSymbol, int pos) {
        List<Symbol> rightList = production.getRight();
        StringBuilder labelBuilder = new StringBuilder();
        Symbol posSymbol = null;
        for (int index = 0; index < rightList.size(); index++) {
            Symbol symbol = rightList.get(index);
            if (index == pos) {
                posSymbol = symbol;
                labelBuilder.append(ITEM_SYMBOL);
            }
            labelBuilder.append(symbol.getLabel());
        }
        if (pos == rightList.size()) {
            posSymbol = Symbol.END;
            labelBuilder.append(ITEM_SYMBOL);
        }
        labelBuilder.append("-");
        labelBuilder.append(expectSymbol.getLabel());
        return new ProductionItem(production, pos, posSymbol, expectSymbol, labelBuilder.toString());
    }

    public List<Symbol> getFirstKeysSymbols() {
        List<Symbol> keySymbols = new ArrayList<>();
        List<Symbol> rightList = production.getRight();
        for (int index = pos + 1; index < rightList.size(); index++) {
            keySymbols.add(rightList.get(index));
        }
        keySymbols.add(expectSymbol);
        return keySymbols;
    }

    public Production getProduction() {
        return production;
    }

    public int getPos() {
        return pos;
    }

    public Symbol getPosSymbol() {
        return posSymbol;
    }

    public Symbol getExpectSymbol() {
        return expectSymbol;
    }

    public String getLabel() {
        return label;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ProductionItem that = (ProductionItem) o;
        return label.equals(that.label);
    }

    @Override
    public int hashCode() {
        return Objects.hash(label);
    }

    @Override
    public int compareTo(ProductionItem o) {
        return label.compareTo(o.label);
    }

    @Override
    public String toString() {
        return label;
    }
}
